package com.ddxz.hetong.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.ddxz.hetong.dto.electicity.CostDto;
import com.ddxz.hetong.dto.electicity.OtherDto;
import com.ddxz.hetong.entity.ElectricExcelEntity;
import com.ddxz.hetong.entity.ElectricInputEntity;
import com.ddxz.hetong.enums.HeTongErrorStatus;
import com.ddxz.hetong.mapper.ElectricityMapper;
import com.ddxz.hetong.service.ElectricityService;
import com.ddxz.tool.core.common.CommonUtil;
import com.ddxz.tool.core.convert.BeanUtil;
import com.ddxz.tool.web.dto.DdxzResponse;
import com.ddxz.tool.web.dto.PageResponse;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.ddxz.hetong.enums.HeTongConst.*;

/**
 * class description
 *
 * @author 贾书虫
 * @version 1.0.0
 * @date 2022/8/1
 */

@Service
public class ElectricityServiceImpl implements ElectricityService {
    /**
     * 获取全部收入
     *
     * @param year    年份
     * @param month   月份
     * @param factory 发电厂名称
     * @param type
     * @return 列表
     */
    @Override
    public DdxzResponse getAllImport(Integer year, Integer month, String factory, Integer type) {
        return getStatistic(year, month, factory, IMPORT_LIST, type);
    }

    /**
     * 获取详情数据
     *
     * @param year     年份
     * @param month    月份
     * @param factory  发电厂名称
     * @param name     财务项名称
     * @param pageNum  页码
     * @param pageSize 页码大小
     * @return 列表
     */
    @Override
    public DdxzResponse getdetail(Integer year, Integer month, String factory, List<String> name, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Page<CostDto> list = mapper.getDetail(year, month, factory, name);
        PageResponse rst = new PageResponse(list.getResult().size());
        rst.setList(list.getResult());
        rst.setTotalElements(list.getTotal());
        rst.setTotalPage(list.getPages());
        return DdxzResponse.correct(rst);
    }

    /**
     * 获取name指定的各项指标，可以指定多个指标
     *
     * @param year    年份
     * @param month   月份
     * @param factory 发电厂名称
     * @param name    统计指标名称
     * @param type
     * @return 列表
     */
    @Override
    public DdxzResponse getStatistic(Integer year, Integer month, String factory, List<String> name, Integer type) {
            List<CostDto> stat = mapper.getStatistic(year, month, factory, name, type);
            return DdxzResponse.correct(stat);
    }

    /**
     * 获取name指定的各项指标，可以指定多个指标
     *
     * @param year    年份
     * @param month   月份
     * @param factory 发电厂名称
     * @param type
     * @return 列表
     */
    @Override
    public DdxzResponse getAllCost(Integer year, Integer month, String factory, Integer type) {
        return getStatistic(year, month, factory, ALL_COST, type);
    }

    /**
     * 获取获取燃料成本之外的成本统计值
     *
     * @param year    年份
     * @param month   月份
     * @param factory 发电厂名称
     * @param type
     * @return 列表
     */
    @Override
    public DdxzResponse getExceptCost(Integer year, Integer month, String factory, Integer type) {
        return getStatistic(year, month, factory, OTHER_COST_LIST, type);
    }

    /**
     * 导入Excel中数据，导入数据会清空原指定年份的数据
     *
     * @param file excel文件
     * @param year 年份
     * @param type 导入数据类型
     * @return 是否导入成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DdxzResponse importExcel(MultipartFile file, Integer year, Integer type) {
        switch (type) {
            case COST_EXCEL:
                return importCostData(file, year);
            case OTHER_EXCEL:
                return importOtherData(file, year);
            default:
                return DdxzResponse.error(HeTongErrorStatus.INVALID_EXCEL_TYPE);
        }
    }

    /**
     * 对比利润与装机容量
     *
     * @param year 年份
     * @param type 粒度
     * @return 列表
     */
    @Override
    public DdxzResponse compare(Integer year, Integer type) {
        List<CostDto> allImport = mapper.getStatistic(year, null, null, IMPORT_LIST, type);
        List<CostDto> allGenerator = mapper.getSampleStatistic(year, null, Arrays.asList(CAPACITY), type);
        Double total = 0.0;
        for (CostDto item : allImport) {
            total += item.getTotal();
        }

        for (CostDto item : allImport) {
            item.setPercent(total < 1e-6 ? 100 : item.getTotal() * 100 / total);
            item.setName(INPUT);
        }

        total = 0.0;
        for (CostDto item : allGenerator) {
            total += item.getTotal();
        }

        for (CostDto item : allGenerator) {
            item.setPercent(total < 1e-6 ? 100 : item.getTotal() * 100 / total);
            item.setName(CAPACITY);
        }

        allGenerator.addAll(allImport);
        return DdxzResponse.correct(allGenerator);
    }

    /**
     * 对比阶段指标
     *
     * @param year 年份
     * @param type 粒度
     * @param stage 阶段
     * @return 列表
     */
    @Override
    public DdxzResponse history(Integer year, Integer type, Integer stage) {
        List<String> names = Arrays.asList(HISTORY_TXA, HISTORY_IMPORT, HISTORY_GENERATOR, HISTORY_HOT);
        List<CostDto> dtoList;
        switch (type) {
            case 1:
                dtoList =mapper.getStageHistory(names);
                break;
            case 2:
                dtoList =mapper.getYearHistory(names, stage);
                break;
            case 3:
                dtoList =mapper.getAllHistory(names, stage);
                break;
            default:
                dtoList = null;
        }
        return DdxzResponse.correct(dtoList);
    }

    /**
     * 盈利能力
     *
     * @param type 类型
     * @param year 年份
     * @return 列表
     */
    @Override
    public DdxzResponse profitability(Integer type, Integer year) {
        List<CostDto> rst = mapper.getTheAblity(type, year, SELF_PROFITABILITY);
        return DdxzResponse.correct(rst);
    }

    /**
     * 偿债能力
     *
     * @param type 类型
     * @param year 年份
     * @return 列表
     */
    @Override
    public DdxzResponse solvency(Integer type, Integer year) {
        List<CostDto> rst = mapper.getTheAblity(type, year, SELF_SOLVENCY);
        return DdxzResponse.correct(rst);
    }

    /**
     * 获利能力
     *
     * @param type 类型
     * @param year 年份
     * @return 列表
     */
    @Override
    public DdxzResponse earning(Integer type, Integer year) {
        List<CostDto> rst = mapper.getTheAblity(type, year, SELF_EARNING);
        return DdxzResponse.correct(rst);
    }

    /**
     * 获利利润分布
     *
     * @param type 类型
     * @param year 年份
     * @return 列表
     */
    @Override
    public DdxzResponse profit(Integer type, Integer year) {
        List<CostDto> rst = mapper.getTheAblity(type, year, SELF_PROFIT);
        return DdxzResponse.correct(rst);
    }

    /**
     * 下载指定的模板文件
     *
     * @param type     1 利润成本模板；2 能力指标模板
     * @param response 下载流
     */
    @Override
    public void downloadTemplate(Integer type, HttpServletResponse response) {
        String fileName = type.equals(COST_EXCEL) ? "利润成本数据导入模板.xlsx" : "能力指标数据导入模板.xlsx";
        String origName = type.equals(OTHER_EXCEL) ? "abilityTemplate.xlsx" : "costTemplate.xlsx";
        response.reset();
        try {
            response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setContentType("application/octet-stream;charset=utf-8");
        byte[] buffer = new byte[8192];

        try (FileInputStream fis = new FileInputStream(path + File.separator + origName);
             OutputStream os = response.getOutputStream()) {
            int length = -1;
            while((length = fis.read(buffer)) > 0) {
                os.write(buffer, 0, length);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取指定年份下的成本占比Top5，燃料成本除外
     *
     * @param year 年份
     * @return 列表
     */
    @Override
    public DdxzResponse costTop5(Integer year) {
        List<CostDto> rst = mapper.getCostTop5(year, "一发");
        rst.addAll(mapper.getCostTop5(year, "三发"));
        return DdxzResponse.correct(rst);
    }

    private DdxzResponse importCostData(MultipartFile file, Integer year) {
        mapper.deleteByYear(year);
        ImportParams params = new ImportParams();
        params.setHeadRows(1);
        try {
            List<ElectricExcelEntity> entities = ExcelImportUtil.importExcel(file.getInputStream(), ElectricExcelEntity.class, params);
            List<CostDto> dtoList = getCostDto(entities);
            mapper.saveYearData(dtoList);
            return DdxzResponse.correct(dtoList);
        } catch (Exception e) {
            e.printStackTrace();
            return DdxzResponse.error(HeTongErrorStatus.INPUT_DATA_ERROR);
        }
    }

    private DdxzResponse importOtherData(MultipartFile file, Integer year) {
        mapper.deleteOtherByYear(year);
        ImportParams params = new ImportParams();
        params.setHeadRows(1);
        try {
            List<ElectricInputEntity> entities = ExcelImportUtil.importExcel(file.getInputStream(), ElectricInputEntity.class, params);
            List<OtherDto> dtoList = getOtherDto(entities);
            mapper.saveOtherYearData(dtoList);
            return DdxzResponse.correct(dtoList);
        } catch (Exception e) {
            e.printStackTrace();
            return DdxzResponse.error(HeTongErrorStatus.INPUT_DATA_ERROR);
        }
    }

    private List<CostDto> getCostDto(List<ElectricExcelEntity> entityList) {
        List<CostDto> dtoList = new ArrayList<>();
        entityList.forEach(entity -> dtoList.addAll(transform(entity)));

        return dtoList;
    }

    private List<OtherDto> getOtherDto(List<ElectricInputEntity> entityList) {
        List<OtherDto> dtoList = new ArrayList<>();
        entityList.forEach(entity -> dtoList.addAll(change(entity)));

        return dtoList;
    }

    private List<OtherDto> change(ElectricInputEntity entity) {
        List<OtherDto> dtoList = new ArrayList<>(13);
        OtherDto dto = new OtherDto();
        dto.setId(CommonUtil.snowId());
        dto.setFactory(entity.getFactory());
        dto.setName(entity.getName());
        dto.setSubname(entity.getSubname());
        dto.setYear(entity.getYear());
        dto.setMonth(null);
        dto.setTotal(entity.getTotal() == null ? 0.0 : entity.getTotal());
        dtoList.add(dto);

        OtherDto tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(1);
        tmp.setTotal(entity.getMonth1() == null ? 0.0 : entity.getMonth1());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(2);
        tmp.setTotal(entity.getMonth2() == null ? 0.0 : entity.getMonth2());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(3);
        tmp.setTotal(entity.getMonth3() == null ? 0.0 : entity.getMonth3());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(4);
        tmp.setTotal(entity.getMonth4() == null ? 0.0 : entity.getMonth4());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(5);
        tmp.setTotal(entity.getMonth5() == null ? 0.0 : entity.getMonth5());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(6);
        tmp.setTotal(entity.getMonth6() == null ? 0.0 : entity.getMonth6());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(7);
        tmp.setTotal(entity.getMonth7() == null ? 0.0 : entity.getMonth7());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(8);
        tmp.setTotal(entity.getMonth8() == null ? 0.0 : entity.getMonth8());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(9);
        tmp.setTotal(entity.getMonth9() == null ? 0.0 : entity.getMonth9());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(10);
        tmp.setTotal(entity.getMonth10() == null ? 0.0 : entity.getMonth10());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(11);
        tmp.setTotal(entity.getMonth11() == null ? 0.0 : entity.getMonth11());
        dtoList.add(tmp);

        tmp = new OtherDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setId(CommonUtil.snowId());
        tmp.setMonth(12);
        tmp.setTotal(entity.getMonth12() == null ? 0.0 : entity.getMonth12());
        dtoList.add(tmp);

        return dtoList;
    }

    private List<CostDto> transform(ElectricExcelEntity entity) {
        List<CostDto> dtoList = new ArrayList<>(12);
        CostDto dto = new CostDto();
        dto.setId(CommonUtil.snowId());
        dto.setYear(entity.getYear());
        dto.setFactory(entity.getFactory());
        dto.setName(entity.getName());
        dto.setMonth(1);
        dto.setSubname(entity.getSubname());
        dto.setDetail(entity.getDetail());
        dto.setTotal(entity.getMonth1() == null ? 0 : entity.getMonth1());
        dtoList.add(dto);

        CostDto tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(2);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth2() == null ? 0 : entity.getMonth2());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(3);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth3() == null ? 0 : entity.getMonth3());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(4);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth4() == null ? 0 : entity.getMonth4());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(5);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth5() == null ? 0 : entity.getMonth5());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(6);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth6() == null ? 0 : entity.getMonth6());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(7);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth7() == null ? 0 : entity.getMonth7());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(8);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth8() == null ? 0 : entity.getMonth8());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(9);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth9() == null ? 0 : entity.getMonth9());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(10);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth10() == null ? 0 : entity.getMonth10());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(11);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth11() == null ? 0 : entity.getMonth11());
        dtoList.add(tmp);

        tmp = new CostDto();
        BeanUtil.copyProperties(dto, tmp);
        tmp.setMonth(12);
        tmp.setId(CommonUtil.snowId());
        tmp.setTotal(entity.getMonth12() == null ? 0 : entity.getMonth12());
        dtoList.add(tmp);

        return dtoList;
    }

    private final ElectricityMapper mapper;
    @Value("${ddxz.template.path}")
    private String path;

    public ElectricityServiceImpl(ElectricityMapper mapper) {
        this.mapper = mapper;
    }
}
